package com.daji.io_nio.selector;

import org.junit.jupiter.api.Test;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;


/*
    该Demo测试方式：
        先启动ServerDemo，ServerDemo的Selector会一直轮询监听
        然后启动ClientDemo，并且在控制台输入数据。此时ServerDemo监听到了，就会在控制台打印输出
* */
public class Server {
    @Test
    public void ServerDemo() throws Exception {
        //1、获取服务端通道 （观察Client代码可知，这里的channel和Client的channel不同）
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();  //这里的channel是 serversocketChannel
        //2、切换非阻塞模式 (同client代码)
        serverSocketChannel.configureBlocking(false);
        //3、创建buffer
        ByteBuffer serverByteBuffer = ByteBuffer.allocate(1024);
        //4、绑定端口号
        serverSocketChannel.bind(new InetSocketAddress("127.0.0.1", 8000));

        //------------------这上面的代码和Client的代码差不多------------------------
        //------------------这下面的代码就是选择器知识点的核心了------------------------

        //5、获取selector选择器
        Selector selector = Selector.open();
        //6、通道注册到选择器，进行监听
        //第二个参数是选择键。有好几种不同的选择键，这里可以自行百度。后面会根据对应的选择键，进行不同的业务逻辑处理。
        //第二个参数是选择键。有好几种不同的选择键，这里可以自行百度。后面会根据对应的选择键，进行不同的业务逻辑处理。
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        //7、选择器进行轮询，进行后续操作
        while(selector.select()>0) {  //如果是1的话，就是就绪状态了。这个轮询类似于事件的监听
            //大吉注：得到到底有几种选择键（到底是哪个选择键被唤醒了）
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            //遍历选择键。
            while (iterator.hasNext()){
                //获取就绪操作
                SelectionKey next = iterator.next();
                //判断是什么操作就绪.NIO 的编程，就是根据对应的选择键，进行不同的业务逻辑处理。
                //判断是什么操作就绪.NIO 的编程，就是根据对应的选择键，进行不同的业务逻辑处理。

                if (next.isAcceptable()){
                    //获取连接 (得到Client的那个SocketChannel,那个SocketChannel里面有写入的数据！)
                    //获取连接 (得到Client的那个SocketChannel,那个SocketChannel里面有写入的数据！)
                    //获取连接 (得到Client的那个SocketChannel,那个SocketChannel里面有写入的数据！)
                    SocketChannel clientChannel = serverSocketChannel.accept();
                    //切换非阻塞模式（上面的切换非阻塞模式是Server的Channel，这个Channel是Client的Channel，和之前不同了）
                    clientChannel.configureBlocking(false);
                    //注册(和上面的注册也不同，这是对Client的Channel注册到选择器中)
                    clientChannel.register(selector, SelectionKey.OP_READ);
                }else if (next.isReadable()){
                    SocketChannel channel = (SocketChannel) next.channel();
                    ByteBuffer byteBuffer1 = ByteBuffer.allocate(1024);
                    //读取数据开始
                    int length = 0;
                    while ((length=channel.read(byteBuffer1))>0){
                        byteBuffer1.flip();
                        System.out.println(new String(byteBuffer1.array(),0,length));
                        byteBuffer1.clear();
                    }
                    //读取并输出数据完毕
                }
            }
            iterator.remove();
        }
    }

}
